MOOC Utils

Utils like auto assignment solver extension and course notice announcment notification for MOOC courses

Authentication API

Introduction#

OTP login, token refresh, logout, and identity endpoints. Auth uses JWT cookies for the session. Request and response shapes, error cases, and how a client should wire the flow are below.

Project structure#

The authentication subsystem is implemented in a FastAPI application with a dedicated router for authentication endpoints. Supporting components include:

  • Configuration and dependency injection
  • Token and OTP persistence models
  • Services for OTP delivery and authentication operations
  • Middleware for CORS and cookie-based session handling

Core components#

  • Authentication router: Exposes endpoints for OTP request, OTP verification, token refresh, logout, and retrieving the current user.
  • Authentication service: Implements OTP lifecycle, JWT access/refresh token creation and validation, refresh token rotation and revocation.
  • Token and OTP models: Persist OTP codes and refresh tokens with expiry and usage tracking.
  • Auth middleware: Extracts access tokens from cookies, validates them, and injects the current user into protected routes.
  • Configuration and dependencies: Centralized settings and dependency factories for services and settings.

Key responsibilities:

  • OTP request: Generates a random code, persists it with expiry, and sends it via configured channel.
  • OTP verification: Validates code and expiry, marks code as used, creates or retrieves user, issues access and refresh tokens, and sets cookies.
  • Token refresh: Accepts a refresh cookie, validates and rotates the token, issues new tokens, and updates cookies.
  • Logout: Revokes refresh token if present and clears auth cookies.
  • Protected routes: Access tokens are validated automatically via middleware.

Architecture overview#

The authentication flow integrates FastAPI routing, Tortoise ORM-backed persistence, and JWT-based tokenization. The client interacts with the API using cookies for session management.

Detailed component analysis#

Authentication endpoints#

  • POST /auth/request-otp

  • Purpose: Request an OTP for the given email address.

  • Request body: OtpRequest { email }

  • Response: OtpRequestResponse { message, is_new_user, expires_at }

  • Behavior: Creates an OTP record with expiry and sends it via configured channel.

  • Security: Rate limiting and input validation are recommended at the application boundary.

  • POST /auth/verify-otp

  • Purpose: Verify the OTP and log in the user.

  • Request body: OtpVerify { email, code }

  • Response: AuthStatus { user, is_new_user }

  • Cookies set: access_token, refresh_token

  • Behavior: Validates OTP, marks as used, creates or retrieves user, issues tokens, and sets cookies.

  • POST /auth/refresh

  • Purpose: Refresh access and refresh tokens using a valid refresh token.

  • Request: Cookie refresh_token

  • Response: AuthStatus { user, is_new_user=false }

  • Cookies set: access_token, refresh_token

  • Behavior: Validates refresh token, rotates it, issues new tokens, and sets cookies.

  • POST /auth/logout

  • Purpose: Log out the user by revoking the refresh token and clearing cookies.

  • Request: Cookie refresh_token

  • Response: 204 No Content

  • Behavior: Revokes refresh token if present and deletes both auth cookies.

  • GET /auth/me

  • Purpose: Retrieve currently authenticated user.

  • Response: UserResponse

  • Behavior: Requires a valid access token cookie; otherwise returns 401.

Request/Response schemas#

  • OtpRequest
  • email: string (validated as email)
  • OtpVerify
  • email: string (validated as email)
  • code: string
  • OtpRequestResponse
  • message: string
  • is_new_user: boolean
  • expires_at: datetime
  • AuthStatus
  • user: UserResponse
  • is_new_user: boolean

Notes:

  • Validation is handled by Pydantic models; invalid payloads will produce structured errors.
  • UserResponse is derived from persisted user model and returned after login or refresh.

JWT token generation and validation#

  • Access token payload includes subject (user ID), email, issued-at, and expiry.
  • Refresh token is a cryptographically random token stored with expiry and revocation flag.
  • Both tokens are signed with HS256 using a secret from settings.

Session management and cookies#

  • Access token cookie: HttpOnly, SameSite=Lax, path=/, secure unless debug.
  • Refresh token cookie: HttpOnly, SameSite=Lax, path=/, secure unless debug.
  • Cookies are set during login and refresh; cleared on logout.
  • Settings control cookie lifetimes and security flags.

Authentication middleware and protected routes#

  • get_current_user extracts access_token from cookies, validates it, and loads the user.
  • require_auth decorator injects current_user into route handlers when present.
  • Unauthorized responses are returned for missing/invalid/expired tokens.

OTP-Based authentication flow#

  • Request OTP: Store OTP with expiry and send via configured channel.
  • Verify OTP: Validate against database constraints, mark used, create or retrieve user, issue tokens, and set cookies.
  • Expiry and uniqueness: OTP records prevent reuse and enforce time limits.

Token refresh flow#

  • Validate refresh token existence and state (not revoked, not expired).
  • Rotate refresh token by marking old as revoked and issuing a new one.
  • Issue new access token and update cookies.

Logout and token revocation#

  • On logout, the refresh token is revoked (marked as revoked) if present.
  • Access and refresh cookies are deleted.

Dependency analysis#

  • Router depends on:
  • Settings for cookie lifetimes and security flags
  • AuthService for OTP, token, and user operations
  • Pydantic schemas for request/response validation
  • AuthService depends on:
  • Settings for token/OTP configuration
  • OtpCode and RefreshToken models for persistence
  • OtpEmailService for OTP delivery
  • OtpEmailService depends on Settings for SMTP configuration or console output.

Performance considerations#

  • Token lifetimes: Access tokens are short-lived; refresh tokens are longer-lived but rotated on each refresh.
  • Database queries: OTP lookup filters by email, code, expiry, and usage; ensure appropriate indexing on OTP table.
  • Cookie security: Secure flags depend on debug mode; in production, cookies should be secure and same-site policies should be enforced.
  • Email delivery: Console delivery is suitable for development; SMTP requires proper credentials and network configuration.

Troubleshooting guide#

Common errors and resolutions:

  • 400 Bad Request on OTP verification: Occurs when OTP is invalid, expired, or already used.
  • 401 Unauthorized on protected routes: Missing, invalid, or expired access token.
  • 401 Unauthorized on refresh: Missing or invalid refresh token, revoked token, or expired token.
  • 401 Unauthorized on logout: Provided refresh token not found or already revoked.
  • Missing SMTP configuration: OTP delivery via SMTP fails if required settings are not provided.

Operational checks:

  • Confirm jwt_secret is set in environment.
  • Verify OTP delivery method and SMTP settings if using email.
  • Ensure database migrations are applied for OTP and refresh token tables.

Conclusion#

OTP in, JWT cookies out. Keep access tokens short-lived, rotate refresh tokens, and never log OTPs or raw tokens in client code.

Appendices#

Endpoint reference#

  • POST /auth/request-otp

  • Request: OtpRequest { email }

  • Response: OtpRequestResponse { message, is_new_user, expires_at }

  • POST /auth/verify-otp

  • Request: OtpVerify { email, code }

  • Response: AuthStatus { user, is_new_user }

  • Cookies: access_token, refresh_token

  • POST /auth/refresh

  • Request: Cookie refresh_token

  • Response: AuthStatus { user, is_new_user=false }

  • Cookies: access_token, refresh_token

  • POST /auth/logout

  • Request: Cookie refresh_token

  • Response: 204 No Content

  • Side effect: Deletes access_token and refresh_token cookies

  • GET /auth/me

  • Response: UserResponse

  • Requires: access_token cookie

Configuration options#

  • jwt_secret: Required for signing tokens
  • jwt_access_token_expire_minutes: Access token lifetime
  • jwt_refresh_token_expire_days: Refresh token lifetime
  • otp_expire_minutes: OTP validity window
  • otp_delivery: “console” or “smtp”
  • smtp_*: SMTP credentials for OTP emails
  • cors_origins: Allowed origins for CORS

Integration patterns#

  • Frontend:
  • Submit email to /auth/request-otp.
  • Prompt user for OTP; submit to /auth/verify-otp.
  • Store cookies automatically; send subsequent requests with credentials.
  • On token expiry, call /auth/refresh using existing refresh_token cookie.
  • On logout, call /auth/logout and clear local state.
  • Backend:
  • Use get_current_user dependency for protected endpoints.
  • Respect require_auth decorator for route protection.
  • Configure Settings for secrets and delivery preferences.